home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / PEAR / Registry.php < prev    next >
PHP Script  |  2004-10-01  |  15KB  |  534 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Bakken <ssb@php.net>                                    |
  17. // |         Tomas V.V.Cox <cox@idecnet.com>                              |
  18. // |                                                                      |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: Registry.php,v 1.50 2004/01/08 17:33:12 sniper Exp $
  22.  
  23. /*
  24. TODO:
  25.     - Transform into singleton()
  26.     - Add application level lock (avoid change the registry from the cmdline
  27.       while using the GTK interface, for ex.)
  28. */
  29. require_once "System.php";
  30. require_once "PEAR.php";
  31.  
  32. define('PEAR_REGISTRY_ERROR_LOCK',   -2);
  33. define('PEAR_REGISTRY_ERROR_FORMAT', -3);
  34. define('PEAR_REGISTRY_ERROR_FILE',   -4);
  35.  
  36. /**
  37.  * Administration class used to maintain the installed package database.
  38.  */
  39. class PEAR_Registry extends PEAR
  40. {
  41.     // {{{ properties
  42.  
  43.     /** Directory where registry files are stored.
  44.      * @var string
  45.      */
  46.     var $statedir = '';
  47.  
  48.     /** File where the file map is stored
  49.      * @var string
  50.      */
  51.     var $filemap = '';
  52.  
  53.     /** Name of file used for locking the registry
  54.      * @var string
  55.      */
  56.     var $lockfile = '';
  57.  
  58.     /** File descriptor used during locking
  59.      * @var resource
  60.      */
  61.     var $lock_fp = null;
  62.  
  63.     /** Mode used during locking
  64.      * @var int
  65.      */
  66.     var $lock_mode = 0; // XXX UNUSED
  67.  
  68.     /** Cache of package information.  Structure:
  69.      * array(
  70.      *   'package' => array('id' => ... ),
  71.      *   ... )
  72.      * @var array
  73.      */
  74.     var $pkginfo_cache = array();
  75.  
  76.     /** Cache of file map.  Structure:
  77.      * array( '/path/to/file' => 'package', ... )
  78.      * @var array
  79.      */
  80.     var $filemap_cache = array();
  81.  
  82.     // }}}
  83.  
  84.     // {{{ constructor
  85.  
  86.     /**
  87.      * PEAR_Registry constructor.
  88.      *
  89.      * @param string (optional) PEAR install directory (for .php files)
  90.      *
  91.      * @access public
  92.      */
  93.     function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR)
  94.     {
  95.         parent::PEAR();
  96.         $ds = DIRECTORY_SEPARATOR;
  97.         $this->install_dir = $pear_install_dir;
  98.         $this->statedir = $pear_install_dir.$ds.'.registry';
  99.         $this->filemap  = $pear_install_dir.$ds.'.filemap';
  100.         $this->lockfile = $pear_install_dir.$ds.'.lock';
  101.  
  102.         // XXX Compatibility code should be removed in the future
  103.         // rename all registry files if any to lowercase
  104.         if (!OS_WINDOWS && $handle = @opendir($this->statedir)) {
  105.             $dest = $this->statedir . DIRECTORY_SEPARATOR;
  106.             while (false !== ($file = readdir($handle))) {
  107.                 if (preg_match('/^.*[A-Z].*\.reg$/', $file)) {
  108.                     rename($dest . $file, $dest . strtolower($file));
  109.                 }
  110.             }
  111.             closedir($handle);
  112.         }
  113.         if (!file_exists($this->filemap)) {
  114.             $this->rebuildFileMap();
  115.         }
  116.     }
  117.  
  118.     // }}}
  119.     // {{{ destructor
  120.  
  121.     /**
  122.      * PEAR_Registry destructor.  Makes sure no locks are forgotten.
  123.      *
  124.      * @access private
  125.      */
  126.     function _PEAR_Registry()
  127.     {
  128.         parent::_PEAR();
  129.         if (is_resource($this->lock_fp)) {
  130.             $this->_unlock();
  131.         }
  132.     }
  133.  
  134.     // }}}
  135.  
  136.     // {{{ _assertStateDir()
  137.  
  138.     /**
  139.      * Make sure the directory where we keep registry files exists.
  140.      *
  141.      * @return bool TRUE if directory exists, FALSE if it could not be
  142.      * created
  143.      *
  144.      * @access private
  145.      */
  146.     function _assertStateDir()
  147.     {
  148.         if (!@is_dir($this->statedir)) {
  149.             if (!System::mkdir(array('-p', $this->statedir))) {
  150.                 return $this->raiseError("could not create directory '{$this->statedir}'");
  151.             }
  152.         }
  153.         return true;
  154.     }
  155.  
  156.     // }}}
  157.     // {{{ _packageFileName()
  158.  
  159.     /**
  160.      * Get the name of the file where data for a given package is stored.
  161.      *
  162.      * @param string package name
  163.      *
  164.      * @return string registry file name
  165.      *
  166.      * @access public
  167.      */
  168.     function _packageFileName($package)
  169.     {
  170.         return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  171.     }
  172.  
  173.     // }}}
  174.     // {{{ _openPackageFile()
  175.  
  176.     function _openPackageFile($package, $mode)
  177.     {
  178.         $this->_assertStateDir();
  179.         $file = $this->_packageFileName($package);
  180.         $fp = @fopen($file, $mode);
  181.         if (!$fp) {
  182.             return null;
  183.         }
  184.         return $fp;
  185.     }
  186.  
  187.     // }}}
  188.     // {{{ _closePackageFile()
  189.  
  190.     function _closePackageFile($fp)
  191.     {
  192.         fclose($fp);
  193.     }
  194.  
  195.     // }}}
  196.     // {{{ rebuildFileMap()
  197.  
  198.     function rebuildFileMap()
  199.     {
  200.         $packages = $this->listPackages();
  201.         $files = array();
  202.         foreach ($packages as $package) {
  203.             $version = $this->packageInfo($package, 'version');
  204.             $filelist = $this->packageInfo($package, 'filelist');
  205.             if (!is_array($filelist)) {
  206.                 continue;
  207.             }
  208.             foreach ($filelist as $name => $attrs) {
  209.                 if (isset($attrs['role']) && $attrs['role'] != 'php') {
  210.                     continue;
  211.                 }
  212.                 if (isset($attrs['baseinstalldir'])) {
  213.                     $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  214.                 } else {
  215.                     $file = $name;
  216.                 }
  217.                 $file = preg_replace(',^/+,', '', $file);
  218.                 $files[$file] = $package;
  219.             }
  220.         }
  221.         $this->_assertStateDir();
  222.         $fp = @fopen($this->filemap, 'wb');
  223.         if (!$fp) {
  224.             return false;
  225.         }
  226.         $this->filemap_cache = $files;
  227.         fwrite($fp, serialize($files));
  228.         fclose($fp);
  229.         return true;
  230.     }
  231.  
  232.     // }}}
  233.     // {{{ readFileMap()
  234.  
  235.     function readFileMap()
  236.     {
  237.         $fp = @fopen($this->filemap, 'r');
  238.         if (!$fp) {
  239.             return $this->raiseError('PEAR_Registry: could not open filemap', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
  240.         }
  241.         $fsize = filesize($this->filemap);
  242.         $rt = get_magic_quotes_runtime();
  243.         set_magic_quotes_runtime(0);
  244.         $data = fread($fp, $fsize);
  245.         set_magic_quotes_runtime($rt);
  246.         fclose($fp);
  247.         $tmp = unserialize($data);
  248.         if (!$tmp && $fsize > 7) {
  249.             return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
  250.         }
  251.         $this->filemap_cache = $tmp;
  252.         return true;
  253.     }
  254.  
  255.     // }}}
  256.     // {{{ _lock()
  257.  
  258.     /**
  259.      * Lock the registry.
  260.      *
  261.      * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  262.      *                See flock manual for more information.
  263.      *
  264.      * @return bool TRUE on success, FALSE if locking failed, or a
  265.      *              PEAR error if some other error occurs (such as the
  266.      *              lock file not being writable).
  267.      *
  268.      * @access private
  269.      */
  270.     function _lock($mode = LOCK_EX)
  271.     {
  272.         if (!eregi('Windows 9', php_uname())) {
  273.             if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
  274.                 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  275.                 return true;
  276.             }
  277.             if (PEAR::isError($err = $this->_assertStateDir())) {
  278.                 return $err;
  279.             }
  280.             $open_mode = 'w';
  281.             // XXX People reported problems with LOCK_SH and 'w'
  282.             if ($mode === LOCK_SH || $mode === LOCK_UN) {
  283.                 if (@!is_file($this->lockfile)) {
  284.                     touch($this->lockfile);
  285.                 }
  286.                 $open_mode = 'r';
  287.             }
  288.  
  289.             $this->lock_fp = @fopen($this->lockfile, $open_mode);
  290.  
  291.             if (!is_resource($this->lock_fp)) {
  292.                 return $this->raiseError("could not create lock file" .
  293.                                          (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  294.             }
  295.             if (!(int)flock($this->lock_fp, $mode)) {
  296.                 switch ($mode) {
  297.                     case LOCK_SH: $str = 'shared';    break;
  298.                     case LOCK_EX: $str = 'exclusive'; break;
  299.                     case LOCK_UN: $str = 'unlock';    break;
  300.                     default:      $str = 'unknown';   break;
  301.                 }
  302.                 return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  303.                                          PEAR_REGISTRY_ERROR_LOCK);
  304.             }
  305.         }
  306.         return true;
  307.     }
  308.  
  309.     // }}}
  310.     // {{{ _unlock()
  311.  
  312.     function _unlock()
  313.     {
  314.         $ret = $this->_lock(LOCK_UN);
  315.         $this->lock_fp = null;
  316.         return $ret;
  317.     }
  318.  
  319.     // }}}
  320.     // {{{ _packageExists()
  321.  
  322.     function _packageExists($package)
  323.     {
  324.         return file_exists($this->_packageFileName($package));
  325.     }
  326.  
  327.     // }}}
  328.     // {{{ _packageInfo()
  329.  
  330.     function _packageInfo($package = null, $key = null)
  331.     {
  332.         if ($package === null) {
  333.             return array_map(array($this, '_packageInfo'),
  334.                              $this->_listPackages());
  335.         }
  336.         $fp = $this->_openPackageFile($package, 'r');
  337.         if ($fp === null) {
  338.             return null;
  339.         }
  340.         $rt = get_magic_quotes_runtime();
  341.         set_magic_quotes_runtime(0);
  342.         $data = fread($fp, filesize($this->_packageFileName($package)));
  343.         set_magic_quotes_runtime($rt);
  344.         $this->_closePackageFile($fp);
  345.         $data = unserialize($data);
  346.         if ($key === null) {
  347.             return $data;
  348.         }
  349.         if (isset($data[$key])) {
  350.             return $data[$key];
  351.         }
  352.         return null;
  353.     }
  354.  
  355.     // }}}
  356.     // {{{ _listPackages()
  357.  
  358.     function _listPackages()
  359.     {
  360.         $pkglist = array();
  361.         $dp = @opendir($this->statedir);
  362.         if (!$dp) {
  363.             return $pkglist;
  364.         }
  365.         while ($ent = readdir($dp)) {
  366.             if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
  367.                 continue;
  368.             }
  369.             $pkglist[] = substr($ent, 0, -4);
  370.         }
  371.         return $pkglist;
  372.     }
  373.  
  374.     // }}}
  375.  
  376.     // {{{ packageExists()
  377.  
  378.     function packageExists($package)
  379.     {
  380.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  381.             return $e;
  382.         }
  383.         $ret = $this->_packageExists($package);
  384.         $this->_unlock();
  385.         return $ret;
  386.     }
  387.  
  388.     // }}}
  389.     // {{{ packageInfo()
  390.  
  391.     function packageInfo($package = null, $key = null)
  392.     {
  393.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  394.             return $e;
  395.         }
  396.         $ret = $this->_packageInfo($package, $key);
  397.         $this->_unlock();
  398.         return $ret;
  399.     }
  400.  
  401.     // }}}
  402.     // {{{ listPackages()
  403.  
  404.     function listPackages()
  405.     {
  406.         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  407.             return $e;
  408.         }
  409.         $ret = $this->_listPackages();
  410.         $this->_unlock();
  411.         return $ret;
  412.     }
  413.  
  414.     // }}}
  415.     // {{{ addPackage()
  416.  
  417.     function addPackage($package, $info)
  418.     {
  419.         if ($this->packageExists($package)) {
  420.             return false;
  421.         }
  422.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  423.             return $e;
  424.         }
  425.         $fp = $this->_openPackageFile($package, 'wb');
  426.         if ($fp === null) {
  427.             $this->_unlock();
  428.             return false;
  429.         }
  430.         $info['_lastmodified'] = time();
  431.         fwrite($fp, serialize($info));
  432.         $this->_closePackageFile($fp);
  433.         $this->_unlock();
  434.         return true;
  435.     }
  436.  
  437.     // }}}
  438.     // {{{ deletePackage()
  439.  
  440.     function deletePackage($package)
  441.     {
  442.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  443.             return $e;
  444.         }
  445.         $file = $this->_packageFileName($package);
  446.         $ret = @unlink($file);
  447.         $this->rebuildFileMap();
  448.         $this->_unlock();
  449.         return $ret;
  450.     }
  451.  
  452.     // }}}
  453.     // {{{ updatePackage()
  454.  
  455.     function updatePackage($package, $info, $merge = true)
  456.     {
  457.         $oldinfo = $this->packageInfo($package);
  458.         if (empty($oldinfo)) {
  459.             return false;
  460.         }
  461.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  462.             return $e;
  463.         }
  464.         $fp = $this->_openPackageFile($package, 'w');
  465.         if ($fp === null) {
  466.             $this->_unlock();
  467.             return false;
  468.         }
  469.         $info['_lastmodified'] = time();
  470.         if ($merge) {
  471.             fwrite($fp, serialize(array_merge($oldinfo, $info)));
  472.         } else {
  473.             fwrite($fp, serialize($info));
  474.         }
  475.         $this->_closePackageFile($fp);
  476.         if (isset($info['filelist'])) {
  477.             $this->rebuildFileMap();
  478.         }
  479.         $this->_unlock();
  480.         return true;
  481.     }
  482.  
  483.     // }}}
  484.     // {{{ checkFileMap()
  485.  
  486.     /**
  487.      * Test whether a file belongs to a package.
  488.      *
  489.      * @param string $path file path, absolute or relative to the pear
  490.      * install dir
  491.      *
  492.      * @return string which package the file belongs to, or an empty
  493.      * string if the file does not belong to an installed package
  494.      *
  495.      * @access public
  496.      */
  497.     function checkFileMap($path)
  498.     {
  499.         if (is_array($path)) {
  500.             static $notempty;
  501.             if (empty($notempty)) {
  502.                 $notempty = create_function('$a','return !empty($a);');
  503.             }
  504.             $pkgs = array();
  505.             foreach ($path as $name => $attrs) {
  506.                 if (is_array($attrs) && isset($attrs['baseinstalldir'])) {
  507.                     $name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  508.                 }
  509.                 $pkgs[$name] = $this->checkFileMap($name);
  510.             }
  511.             return array_filter($pkgs, $notempty);
  512.         }
  513.         if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) {
  514.             return $err;
  515.         }
  516.         if (isset($this->filemap_cache[$path])) {
  517.             return $this->filemap_cache[$path];
  518.         }
  519.         $l = strlen($this->install_dir);
  520.         if (substr($path, 0, $l) == $this->install_dir) {
  521.             $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
  522.         }
  523.         if (isset($this->filemap_cache[$path])) {
  524.             return $this->filemap_cache[$path];
  525.         }
  526.         return '';
  527.     }
  528.  
  529.     // }}}
  530.  
  531. }
  532.  
  533. ?>
  534.